#include "Tester.h"

MemoryManager Tester::mmFuncion;
MemoryManager Tester::mmParametros;

Tester::Tester() {
}

int Tester::main(const char* nombreArchivoDefinicion, ostream& out){
    ifstream archivoDefinicion(nombreArchivoDefinicion, ios::in);

    if ( !archivoDefinicion.is_open() ) {
        cout << "Error abriendo el archivo de definicion" << endl;
        return 1;
    }

    FuncionesAuxiliares::parseaFuncion(archivoDefinicion, _funcion);

    archivoDefinicion.close();

    armarCasosDeTest();

    ejecutarCasosDeTest(out);

    return 0;
}

void Tester::ejecutarCasosDeTest(ostream& out){
    list<CasoDeTest>::iterator iter;
    bool ok;
    int i = 0;

    for( iter = _casosDeTest.begin(); iter != _casosDeTest.end(); iter++ ) {
        out << "EJECUTANDO CASO DE TEST NUMERO " << i + 1 << " :" << endl;
        out << "==================================" << endl;
        ok = ejecutarCasoDeTest(*iter,out);
        out << endl << endl;
        i++;
        if ( !ok )
            return;
    }
}

void Tester::agregarCasoDeTest(CasoDeTest& casoDeTest){
    _casosDeTest.push_back(casoDeTest);
}

bool Tester::ejecutarCasoDeTest(CasoDeTest& casoDeTest, ostream& out){

    // inicializar el ambiente del test
    configurarTest();

    // correr la funcion a evaluar
    _medidor.inicializar();
    _funcion.evaluar(casoDeTest);
    _medidor.finalizar();

    // finalizar el ambiente del test
    finalizarTest();

    // comparar el resultado esperado contra el obtenido de la salida}
    if( casoDeTest.getSalidaObtenida() != NULL ) {
        out << endl << endl << "Resultados para la salida esperada/obtenida:" << endl;
        out << "--------------------------------------------" << endl << endl;
        casoDeTest.getSalidaEsperada()->comparar(*(casoDeTest.getSalidaObtenida()),out);
    }

    // comparar el resultado esperado contra el obtenido de los parametros in/out
    out << endl << endl << "Resultados para los parametros IN/OUT:" << endl;
    out << "--------------------------------------" << endl << endl;
    vector<Parametro>::iterator it;
    unsigned int i = 0;
    unsigned int j = 0;
    for ( it = _funcion.getParametros().begin(); it != _funcion.getParametros().end(); it++ ) {
        if ( it->getEsOut() ) {
            if ( j >= casoDeTest.getParametros().size() )  {
                out << "Error. Hay menos parametros de los esperados." << endl;
                return false;
            }
            if ( i >= casoDeTest.getSalidasInOut().size() ) {
                out << "Error. Hay menos salidas in/out de los esperadas." << endl;
                return false;
            }
            out << "Parametro IN/OUT numero " << j + 1 << " :" << endl << endl;
            (casoDeTest.getSalidasInOut()[i])->comparar(*(casoDeTest.getParametros()[j]),out);
            i++;
        }
        j++;
    }

    // Ver si dieron bien los free de la funcion
    list<RegistroMalloc>& registrosFuncion = Tester::mmFuncion.getRegistrosMalloc();
    list<RegistroMalloc>::iterator it2;
    int nPincho = 0;
    int nBien = 0;

    for ( it2 = registrosFuncion.begin(); it2 != registrosFuncion.end(); it2++ ) {
        if ( it2->getPincho() ) {
            nPincho++;
        } else {
            nBien++;
        }
    }

    if ( nPincho > 0 ) {
        out << endl << endl << "MEMORIA (dentro de la funcion):" << endl;
        out << "-------------------------------" << endl << endl;
        out << "En este test se llamo a free " << nPincho + nBien << " veces. Free fue ejecutado " << nBien << " veces de forma correcta y " << nPincho << " veces de forma incorrecta." << endl;
        return false;
    }


    // Ver si dieron bien los free de los parametros
    list<RegistroMalloc*> registrosParametros;
    list<RegistroMalloc*>::iterator it3;
    Tester::mmParametros.getRegistrosMalloc(registrosParametros, casoDeTest);
    nPincho = 0;
    nBien = 0;

    // liberar la memoria (falsamente) de los tipos de dato
    casoDeTest.liberarMemoriaParametros();

    for ( it3 = registrosParametros.begin(); it3 != registrosParametros.end(); it3++ ) {
        if ( (*it3)->getPincho() ) {
            nPincho++;
        } else {
            nBien++;
        }
    }

    if ( nPincho > 0 ) {
        out << endl << endl << "MEMORIA (de los parametros):" << endl;
        out << "----------------------------" << endl << endl;
        out << "En este test se llamo a free " << nPincho + nBien << " veces. Free fue ejecutado " << nBien << " veces de forma correcta y " << nPincho << " veces de forma incorrecta." << endl;
        return false;
    }

    // Resultados del Medidor
    out << endl << endl << "MEDICIONES:" << endl;
    out << "-----------" << endl << endl;
    out << "La funcion a evaluar tardo " << _medidor.getCiclos() << " ciclos de CPU en total." << endl;

    // liberar la memoria que pidio la funcion
    Tester::mmFuncion.hacerFree();
    //Tester::mmParametros.hacerFree(casoDeTest);

    return true;
}
